/*
 * Copyright (c) 2024 Shenzhen Kaihong Digital Industry Development Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "sle_announce_service.h"
#include "sle_announce_hal.h"
#include "sle_host_hal.h"
#include "sle_hilog.h"

namespace OHOS {
namespace NearLink {
namespace SleStandard {

class SleAnnounceService::SleAnnounceServiceCallback {
public:
    SleAnnounceServiceCallback() = default;
    ~SleAnnounceServiceCallback() = default;

    static void OnAnnounceStartResult(uint8_t announceId, SleHalErrorCode errCode);
    static void OnAnnounceStopResult(uint8_t announceId, SleHalErrorCode errCode);
    static void OnAnnounceTerminal(uint8_t announceId);
    static void OnAnnounceRemoveResult(uint8_t announceId, SleHalErrorCode errCode);
    static SleAnnounceHalCallbacks *BuildHalAnnounceCallback();

private:
    static SleAnnounceHalCallbacks halCallback_;
};

void SleAnnounceService::SleAnnounceServiceCallback::OnAnnounceStartResult(uint8_t announceId, SleHalErrorCode errCode)
{
    auto anneService = SleAnnounceService::GetInstance();
    SLE_ASSERT_AND_RETURN_LOG(anneService, "announce service instance null error!");
    SLE_ASSERT_AND_RETURN_LOG(anneService->callback_, "announce service callback null error!");
    SleAnnounceState state = (errCode == SLE_HAL_SUCCESS) ? SLE_ANNOUNCE_ENABLED_STATE : SLE_ANNOUNCE_ERROR_STATE;
    anneService->callback_->OnAnnounceStateChange(announceId, state, false);
}

void SleAnnounceService::SleAnnounceServiceCallback::OnAnnounceStopResult(uint8_t announceId, SleHalErrorCode errCode)
{
    auto anneService = SleAnnounceService::GetInstance();
    SLE_ASSERT_AND_RETURN_LOG(anneService, "announce service instance null error!");
    SLE_ASSERT_AND_RETURN_LOG(anneService->callback_, "announce service callback null error!");
    SleAnnounceState state = (errCode == SLE_HAL_SUCCESS) ? SLE_ANNOUNCE_DISABLED_STATE : SLE_ANNOUNCE_ERROR_STATE;
    anneService->callback_->OnAnnounceStateChange(announceId, state, false);
}

void SleAnnounceService::SleAnnounceServiceCallback::OnAnnounceTerminal(uint8_t announceId)
{
    auto anneService = SleAnnounceService::GetInstance();
    SLE_ASSERT_AND_RETURN_LOG(anneService, "announce service instance null error!");
    SLE_ASSERT_AND_RETURN_LOG(anneService->callback_, "announce service callback null error!");
    anneService->callback_->OnAnnounceStateChange(announceId, SLE_ANNOUNCE_DISABLED_STATE, true);
}

void SleAnnounceService::SleAnnounceServiceCallback::OnAnnounceRemoveResult(uint8_t announceId, SleHalErrorCode errCode)
{
    SLE_LOGD("announceId:%d, result:%x", announceId, errCode);
}

SleAnnounceHalCallbacks SleAnnounceService::SleAnnounceServiceCallback::halCallback_;
SleAnnounceHalCallbacks *SleAnnounceService::SleAnnounceServiceCallback::BuildHalAnnounceCallback()
{
    SLE_LOGD("BuildHalConnectCallback In");
    halCallback_.OnAnnounceHalStartAnnounceCb = OnAnnounceStartResult;
    halCallback_.OnAnnounceHalStopAnnounceCb = OnAnnounceStopResult;
    halCallback_.OnAnnounceHalTerminalAnnounceCb = OnAnnounceTerminal;
    halCallback_.OnAnnounceHalRemoveAnnounceCb = OnAnnounceRemoveResult;
    return &halCallback_;
}

SleAnnounceService::SleAnnounceService()
{
    SLE_LOGD("SleAnnounceService In");
    SleHalErrorCode ret = InitSleAnnounceHal();
    SLE_ASSERT_AND_RETURN_LOG(ret == SLE_HAL_SUCCESS, "init sle announce hal failed!");
    serviceCallback_ = std::make_unique<SleAnnounceServiceCallback>();
    SLE_ASSERT_AND_RETURN_LOG(serviceCallback_, "create service callback ptr failed!");
    ret = SleAnnounceHalRegisterCallbacks(serviceCallback_->BuildHalAnnounceCallback());
    SLE_ASSERT_AND_RETURN_LOG(ret == SLE_HAL_SUCCESS, "register hal announce callback failed!");
}

SleAnnounceService::~SleAnnounceService()
{
    SLE_LOGD("~SleAnnounceService In");
    SleHalErrorCode ret = DeinitSleAnnounceHal();
    SLE_ASSERT_AND_RETURN_LOG(ret == SLE_HAL_SUCCESS, "deinit sle announce hal failed!");
    serviceCallback_ = nullptr;
}

SleAnnounceService *SleAnnounceService::GetInstance()
{
    static SleAnnounceService instance;
    return &instance;
}

SleErrorCode SleAnnounceService::StartAnnounce(uint8_t announceId, AnnounceData &data, AnnounceParam &param)
{
    SLE_LOGD("StartAnnounce In");
    SleAnnounceData datas;
    data.ConvertToSleAnnounceData(datas);
    SleHalErrorCode ret = SleAnnounceHalSetAnnounceData(announceId, &datas);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_HAL_SUCCESS, SLE_ERR_FAILED, "set announce data failed!");

    SleAnnounceParam params;
    param.ConvertToSleAnnounceParam(params);
    ret = SleHostHalGetHostAddress(&params.ownAddr);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_HAL_SUCCESS, SLE_ERR_FAILED, "set announce own address failed!");

    ret = SleAnnounceHalSetAnnounceParam(announceId, &params);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_HAL_SUCCESS, SLE_ERR_FAILED, "set announce param failed!");

    ret = SleAnnounceHalStartAnnounce(announceId);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_HAL_SUCCESS, SLE_ERR_FAILED, "start announce failed!");
    return SLE_NO_ERROR;
}

SleErrorCode SleAnnounceService::StopAnnounce(uint8_t announceId)
{
    SLE_LOGD("StopAnnounce In");
    SleHalErrorCode ret = SleAnnounceHalStopAnnounce(announceId);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_HAL_SUCCESS, SLE_ERR_FAILED, "stop announce failed!");
    return SLE_NO_ERROR;
}

SleErrorCode SleAnnounceService::RegisterAnnounceCallback(IAnnounceCallback &callback)
{
    SLE_LOGD("RegisterAnnounceCallback In");
    SLE_ASSERT_AND_RETURN_RET_LOG(callback_ != &callback, SLE_ERR_INVALID_PARAM, "callback already registered error!");
    callback_ = &callback;
    return SLE_NO_ERROR;
}

SleErrorCode SleAnnounceService::UnregisterAnnounceCallback(IAnnounceCallback &callback)
{
    SLE_LOGD("UnregisterAnnounceCallback In");
    SLE_ASSERT_AND_RETURN_RET_LOG(callback_ == &callback, SLE_ERR_INVALID_PARAM, "callback already unregistered error!");
    callback_ = nullptr;
    return SLE_NO_ERROR;
}
} // SleStandard
} // NearLink
} // OHOS